﻿using System;
using System.Xml;
using System.Collections.Generic;
using System.Text;

using Weazel.Gezel.Model;

namespace Weazel.Gezel.Exporter
{
  internal class SystemExporter
  {
    /// <summary>
    /// Converts a gezel system to its xml representation.
    /// </summary>
    /// <param name="xmlDoc"></param>
    /// <param name="parent"></param>
    /// <param name="system"></param>
    internal static void ToXml(XmlDocument xmlDoc, XmlElement parent, system system)
    {
      XmlElement systemElement = xmlDoc.CreateElement("System");
      systemElement.SetAttribute("name", system.LocalName);
      systemElement.SetAttribute("id", system.Name);

      foreach (system.Net net in system.Nets.Values)
      {
        XmlElement connectionElement = xmlDoc.CreateElement("Connection");
        connectionElement.SetAttribute("name", net.LocalName);
        connectionElement.SetAttribute("id", net.Name);

        XmlElement outputElement = xmlDoc.CreateElement("Output");
        outputElement.SetAttribute("entity", net.OutPort.Parent.LocalName);
        outputElement.SetAttribute("connector", net.OutPort.Name);

        connectionElement.AppendChild(outputElement);

        foreach (InPort inport in net.InPorts)
        {
          XmlElement inputElement = xmlDoc.CreateElement("Input");
          inputElement.SetAttribute("entity", inport.Parent.LocalName);
          inputElement.SetAttribute("connector", inport.Name);

          connectionElement.AppendChild(inputElement);
        }

        systemElement.AppendChild(connectionElement);
      }

      parent.AppendChild(systemElement);
    }

    /// <summary>
    /// Converts a gezel system to its string representation
    /// </summary>
    /// <param name="textWriter"></param>
    /// <param name="system"></param>
    internal static void ToGezel(System.CodeDom.Compiler.IndentedTextWriter textWriter, system system)
    {
      textWriter.WriteLine("system {0}", system.LocalName);
      textWriter.WriteLine("{");

      textWriter.Indent++;

			// add datapaths w/o any connections
			foreach (string unconnectedDatapath in system.UnconnectedDatapaths)
				textWriter.WriteLine("{0};", unconnectedDatapath);
			
			string[] datapaths = system.GetDatapathReferenceNamed();

			foreach(system.DatapathConnectionInfo con in system.PortConnections.Values)
			{
				// find the writing dp or ipblock
				OutPort source = null;
				List<InPort> sinks = new List<InPort>();

				foreach (system.DatapathConnectorInfo connector in con.Connectors)
				{
					Block block = system.Parent.GetBlock(connector.DatapathName);

					Port port = connector.UsingNamedBinding ?
						block.GetPortByLocalName(connector.PortName) :
						block.GetPortAtPosition(connector.DeclarationPosition);

					if (port is OutPort)
						source = port as OutPort;
					else
						sinks.Add(port as InPort);
				}

				foreach (InPort sink in sinks)
					textWriter.WriteLine("{0}.{1} = {2}.{3};", 
						(sink.Parent as Block).LocalName,
						sink.LocalName,
						(source.Parent as Block).LocalName,
						source.LocalName
						);
			}

/*
			foreach (string dpRef in datapaths)
			{
				string[] nets =
					system.GetPositionalBindingList(dpRef);

				if (nets.Length > 0)
				{
					StringBuilder buffer = new StringBuilder();
					foreach (string net in nets)
						buffer.AppendFormat("{0}, ", net);

					buffer.Remove(buffer.Length - 2, 2);
					textWriter.WriteLine("{0}({1});", dpRef, buffer.ToString());
				}
				else
				{
					textWriter.WriteLine("{0};", dpRef);
				}
			}
 * */
			
      textWriter.Indent--;

      textWriter.WriteLine("}");
    }
  }
}
